package com.gitee.wsl.doc.prosemirror.plugin.parser

import com.gitee.wsl.doc.prosemirror.model.Schema
import com.gitee.wsl.doc.prosemirror.model.attr.Attrs
import com.gitee.wsl.ext.map.putIfAbsent
import kotlin.collections.iterator

typealias TokenHandler<Token> = (NodeStack<Token>, Token, List<Token>, Int) -> Unit

abstract class ParserHandler<Token> {
    val handlers = HashMap<String, TokenHandler<Token>>()

    /**
     * 生成Markdown令牌处理器
     * @param schema 模式对象
     * @param tokens 令牌解析规范映射
     * @return 令牌处理器映射
     */
    fun tokenHandlers(
        schema: Schema,
        tokens: Map<String, ParseSpec<Token>>
    ): Map<String, TokenHandler<Token>> {

        for ((type, spec) in tokens) {
            when {
                spec.block != null -> {
                    val nodeType = schema.nodeType(spec.block!!)
                    if (noCloseToken(spec, type)) {
                        handlers[type] = { state, tok, tokens, i ->
                            state.openNode(nodeType, attrs(spec, tok, tokens, i))
                            state.addText(withoutTrailingNewline(getContent(tok)))
                            state.closeNode()
                        }
                    } else {
                        handlers["${type}_open"] = { state, tok, tokens, i ->
                            state.openNode(nodeType, attrs(spec, tok, tokens, i))
                        }
                        handlers["${type}_close"] = { state, tok, tokens, i  -> state.closeNode() }
                    }
                }
                spec.node != null -> {
                    val nodeType = schema.nodeType(spec.node!!)
                    handlers[type] = { state, tok, tokens, i ->
                        state.addNode(nodeType, attrs(spec, tok, tokens, i))
                    }
                }
                spec.mark != null -> {
                    val markType = schema.marks[spec.mark]!!
                    if (noCloseToken(spec, type)) {
                        handlers[type] = { state, tok, tokens, i ->
                            state.openMark(markType.create(attrs(spec, tok, tokens, i)))
                            state.addText(withoutTrailingNewline(getContent(tok)))
                            state.closeMark(markType)
                        }
                    } else {
                        handlers["${type}_open"] = { state, tok, tokens, i ->
                            state.openMark(markType.create(attrs(spec, tok, tokens, i)))
                        }
                        handlers["${type}_close"] = { state, tok, tokens, i  -> state.closeMark(markType) }
                    }
                }
                spec.ignore == true -> {
                   if (noCloseToken(spec, type)) {
                       handlers[type] = noOp
                   } else {
                       handlers["${type}_open"] = noOp
                       handlers["${type}_close"] = noOp
                   }
                }
                else -> throw IllegalArgumentException("Unrecognized parsing spec ${spec.toJsonString()}")
                }
            }

                // 设置默认处理器
                handlers["text"] = { state, tok, _, _ -> state.addText(getContent(tok)) }
                handlers ["inline"] = { state, tok, _, _ ->
                    getChildren(tok)?.let { state.parseTokens(it) }
                }
                handlers.putIfAbsent ("softbreak", { state, _, _, _ -> state.addText(" ") })

                return handlers
            }

           abstract fun getContent(token: Token):String

           abstract fun getChildren(token: Token):List<Token>?

            /**
             * 检查是否为无闭合令牌
             */
            private fun noCloseToken(spec: ParseSpec<Token>, type: String): Boolean {
                return spec.noCloseToken ?: (type == "code_inline" || type == "code_block" || type == "fence")
            }

            /**
             * 获取属性
             */
            private fun attrs(
                spec: ParseSpec<Token>,
                token: Token,
                tokenStream: List<Token>,
                index: Int
            ): Attrs? {
                return spec.getAttrs?.invoke(token, tokenStream, index) ?: spec.attrs
            }

            /**
             * 移除尾部换行符
             */
            private fun withoutTrailingNewline(content: String): String {
                return content.trimEnd('\n', '\r')
            }

            /**
             * 空操作函数
             */
            private val noOp:TokenHandler<Token> = { _, _, _, _ -> }

            /**
             * 将对象转换为JSON字符串（简化实现）
             */
            private fun Any?.toJsonString(): String {
                return when (this) {
                    is String -> "\"$this\""
                    is Number, is Boolean -> this.toString()
                    null -> "null"
                    else -> this.toString()
                }
            }
}